#include <iostream>
#include <string>
#include <vector>
#include <chrono>
#include <thread>
#include <fstream>
#include <filesystem>
#include <ctime>
#include <sstream>
#include <iomanip>
#include <cstdlib>
#include <algorithm>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

struct Repository {
    std::string path;
    std::string branch;
    bool enabled;
};

struct Config {
    std::vector<Repository> repositories;
    int daily_hour;
    int daily_minute;
    std::string commit_message_template;
};

class AutoGitPush {
private:
    Config config;
    bool daemon_mode = false;
    
    void log(const std::string& message) {
        auto now = std::chrono::system_clock::now();
        auto time_t = std::chrono::system_clock::to_time_t(now);
        
        // Convert to Beijing time (UTC+8)
        time_t += 8 * 3600; // Add 8 hours for Beijing time
        auto tm = *std::gmtime(&time_t); // Use gmtime since we already adjusted for timezone
        
        std::stringstream ss;
        ss << "[" << std::put_time(&tm, "%Y-%m-%d %H:%M:%S") << " BJT] " << message;
        std::string log_msg = ss.str();
        
        if (!daemon_mode) {
            std::cout << log_msg << std::endl;
        }
        
        // Always write to log file
        std::ofstream logfile("auto_git_push.log", std::ios::app);
        if (logfile.is_open()) {
            logfile << log_msg << std::endl;
            logfile.close();
        }
    }
    
    void save_config() {
        std::ofstream config_file("config.txt");
        if (config_file.is_open()) {
            config_file << "# 自动Git推送工具配置文件" << std::endl;
            config_file << "daily_hour=" << config.daily_hour << std::endl;
            config_file << "daily_minute=" << config.daily_minute << std::endl;
            config_file << "commit_message=" << config.commit_message_template << std::endl;
            config_file << std::endl;
            
            for (size_t i = 0; i < config.repositories.size(); i++) {
                config_file << "repo" << i << "_path=" << config.repositories[i].path << std::endl;
                config_file << "repo" << i << "_branch=" << config.repositories[i].branch << std::endl;
                config_file << "repo" << i << "_enabled=" << (config.repositories[i].enabled ? "true" : "false") << std::endl;
                config_file << std::endl;
            }
            config_file.close();
            log("配置已保存到 config.txt");
        }
    }
    
    bool load_config() {
        std::ifstream config_file("config.txt");
        if (!config_file.is_open()) {
            return false;
        }
        
        config.repositories.clear();
        std::string line;
        std::vector<Repository> temp_repos;
        
        while (std::getline(config_file, line)) {
            if (line.empty() || line[0] == '#') continue;
            
            size_t equals_pos = line.find('=');
            if (equals_pos == std::string::npos) continue;
            
            std::string key = line.substr(0, equals_pos);
            std::string value = line.substr(equals_pos + 1);
            
            if (key == "daily_hour") {
                config.daily_hour = std::stoi(value);
            } else if (key == "daily_minute") {
                config.daily_minute = std::stoi(value);
            } else if (key == "commit_message") {
                config.commit_message_template = value;
            } else if (key.find("repo") == 0) {
                // Parse repository configuration
                size_t underscore_pos = key.find('_');
                if (underscore_pos != std::string::npos) {
                    std::string repo_index_str = key.substr(4, underscore_pos - 4);
                    std::string repo_field = key.substr(underscore_pos + 1);
                    int repo_index = std::stoi(repo_index_str);
                    
                    // Ensure we have enough repositories in the vector
                    while (temp_repos.size() <= static_cast<size_t>(repo_index)) {
                        temp_repos.push_back(Repository{"", "main", true});
                    }
                    
                    if (repo_field == "path") {
                        temp_repos[repo_index].path = value;
                    } else if (repo_field == "branch") {
                        temp_repos[repo_index].branch = value;
                    } else if (repo_field == "enabled") {
                        temp_repos[repo_index].enabled = (value == "true");
                    }
                }
            }
        }
        
        config.repositories = temp_repos;
        config_file.close();
        return true;
    }
    
    void become_daemon() {
        pid_t pid = fork();
        
        if (pid < 0) {
            log("Fork失败");
            exit(1);
        }
        
        if (pid > 0) {
            // Parent process exits
            exit(0);
        }
        
        // Child process continues
        if (setsid() < 0) {
            log("Setsid失败");
            exit(1);
        }
        
        // Don't change working directory to root, keep current directory for config and log files
        // if (chdir("/") != 0) {
        //     log("改变工作目录失败");
        // }
        
        // Set daemon mode before closing file descriptors
        daemon_mode = true;
        
        // Close standard file descriptors
        close(STDIN_FILENO);
        close(STDOUT_FILENO);
        close(STDERR_FILENO);
        
        log("守护进程已启动");
    }
    
    std::chrono::minutes calculate_minutes_until_next_run() {
        auto now = std::chrono::system_clock::now();
        auto time_t = std::chrono::system_clock::to_time_t(now);
        
        // Convert to Beijing time (UTC+8)
        time_t += 8 * 3600; // Add 8 hours for Beijing time
        auto tm = *std::gmtime(&time_t);
        
        // Calculate target time today in Beijing time
        tm.tm_hour = config.daily_hour;
        tm.tm_min = config.daily_minute;
        tm.tm_sec = 0;
        
        // Convert back to UTC for comparison
        auto target_time_utc = std::chrono::system_clock::from_time_t(std::mktime(&tm) - 8 * 3600);
        
        // If target time has passed today, schedule for tomorrow
        if (target_time_utc <= now) {
            target_time_utc += std::chrono::hours(24);
        }
        
        auto duration = std::chrono::duration_cast<std::chrono::minutes>(target_time_utc - now);
        return duration;
    }
    
    std::string execute_command(const std::string& command, const std::string& working_dir = "") {
        std::string full_command = command;
        if (!working_dir.empty()) {
            full_command = "cd \"" + working_dir + "\" && " + command;
        }
        
        FILE* pipe = popen(full_command.c_str(), "r");
        if (!pipe) {
            return "";
        }
        
        char buffer[128];
        std::string result = "";
        while (fgets(buffer, sizeof buffer, pipe) != nullptr) {
            result += buffer;
        }
        
        int exit_code = pclose(pipe);
        if (exit_code != 0) {
            return "";
        }
        
        // Remove trailing newline
        if (!result.empty() && result.back() == '\n') {
            result.pop_back();
        }
        
        return result;
    }
    
    bool has_changes(const std::string& repo_path) {
        std::string status = execute_command("git status --porcelain", repo_path);
        return !status.empty();
    }
    
    std::string get_current_timestamp() {
        auto now = std::chrono::system_clock::now();
        auto time_t = std::chrono::system_clock::to_time_t(now);
        
        // Convert to Beijing time (UTC+8)
        time_t += 8 * 3600; // Add 8 hours for Beijing time
        auto tm = *std::gmtime(&time_t);
        
        std::stringstream ss;
        ss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S") << " BJT";
        return ss.str();
    }
    
    bool check_branch_exists(const std::string& repo_path, const std::string& branch) {
        std::string local_branch = execute_command("git branch --list " + branch, repo_path);
        if (local_branch.empty()) {
            return false;
        }
        return true;
    }
    
    bool create_and_checkout_branch(const std::string& repo_path, const std::string& branch) {
        std::string create_result = execute_command("git checkout -b " + branch, repo_path);
        if (create_result.empty()) {
            log("创建分支失败: " + branch + " 在 " + repo_path);
            return false;
        }
        log("创建并切换到分支: " + branch + " 在 " + repo_path);
        return true;
    }
    
    std::string get_current_branch(const std::string& repo_path) {
        std::string current_branch = execute_command("git branch --show-current", repo_path);
        return current_branch;
    }
    
    bool commit_and_push(const Repository& repo) {
        if (!std::filesystem::exists(repo.path)) {
            log("仓库路径不存在: " + repo.path);
            return false;
        }
        
        if (!std::filesystem::exists(repo.path + "/.git")) {
            log("不是git仓库: " + repo.path);
            return false;
        }
        
        // Get current branch
        std::string current_branch = get_current_branch(repo.path);
        if (current_branch.empty()) {
            log("无法获取当前分支信息: " + repo.path);
            return false;
        }
        
        // If current branch is different from target branch, switch or create it
        if (current_branch != repo.branch) {
            if (!check_branch_exists(repo.path, repo.branch)) {
                log("目标分支不存在，正在创建: " + repo.branch);
                if (!create_and_checkout_branch(repo.path, repo.branch)) {
                    return false;
                }
            } else {
                // Switch to existing branch
                std::string checkout_result = execute_command("git checkout " + repo.branch, repo.path);
                if (checkout_result.empty()) {
                    log("切换分支失败: " + repo.branch + " 在 " + repo.path);
                    return false;
                }
                log("切换到分支: " + repo.branch + " 在 " + repo.path);
            }
        }
        
        if (!has_changes(repo.path)) {
            log("仓库无变化: " + repo.path);
            return true;
        }
        
        log("正在处理仓库变化: " + repo.path);
        
        // Add all changes
        std::string add_result = execute_command("git add .", repo.path);
        
        // Commit changes
        std::string timestamp = get_current_timestamp();
        std::string commit_msg = config.commit_message_template;
        size_t pos = commit_msg.find("{timestamp}");
        if (pos != std::string::npos) {
            commit_msg.replace(pos, 11, timestamp);
        }
        
        std::string commit_command = "git commit -m \"" + commit_msg + "\"";
        std::string commit_result = execute_command(commit_command, repo.path);
        if (commit_result.empty()) {
            log("提交失败: " + repo.path);
            return false;
        }
        
        // Check if remote exists
        std::string remote_check = execute_command("git remote -v", repo.path);
        if (remote_check.empty()) {
            log("未配置远程仓库: " + repo.path);
            return false;
        }
        
        // Set upstream if it doesn't exist
        std::string upstream_check = execute_command("git rev-parse --abbrev-ref " + repo.branch + "@{upstream}", repo.path);
        if (upstream_check.empty()) {
            log("设置上游分支: origin/" + repo.branch);
            std::string set_upstream = "git push --set-upstream origin " + repo.branch;
            std::string upstream_result = execute_command(set_upstream, repo.path);
            if (upstream_result.empty()) {
                log("设置上游分支失败: " + repo.path);
                return false;
            }
        }
        
        // Push to remote
        std::string push_command = "git push origin " + repo.branch;
        std::string push_result = execute_command(push_command, repo.path);
        
        // Check if push was successful by checking git status
        std::string status_after_push = execute_command("git status", repo.path);
        if (status_after_push.find("Your branch is up to date") != std::string::npos || 
            status_after_push.find("nothing to commit") != std::string::npos) {
            log("成功推送变化到: " + repo.path);
            return true;
        } else {
            log("推送失败: " + repo.path);
            // Log the actual git status for debugging
            log("Git状态: " + status_after_push);
            return false;
        }
    }
    
public:
    AutoGitPush() {
        config.daily_hour = 18;
        config.daily_minute = 0;
        config.commit_message_template = "自动提交: {timestamp}";
        
        // Try to load existing config
        if (load_config()) {
            log("已加载现有配置");
        }
    }
    
    void configure_repositories() {
        std::cout << "\n=== 仓库配置 ===" << std::endl;
        
        int repo_count;
        std::cout << "请输入要监控的仓库数量: ";
        std::cin >> repo_count;
        std::cin.ignore();
        
        config.repositories.clear();
        
        for (int i = 0; i < repo_count; i++) {
            Repository repo;
            
            std::cout << "\n仓库 " << (i + 1) << ":" << std::endl;
            std::cout << "请输入仓库路径: ";
            std::getline(std::cin, repo.path);
            
            std::cout << "请输入分支名称 (默认: main): ";
            std::getline(std::cin, repo.branch);
            if (repo.branch.empty()) {
                repo.branch = "main";
            }
            
            char enabled_input;
            std::cout << "启用此仓库? (y/n, 默认: y): ";
            std::cin >> enabled_input;
            std::cin.ignore();
            repo.enabled = (enabled_input != 'n' && enabled_input != 'N');
            
            config.repositories.push_back(repo);
        }
        
        save_config();
    }
    
    void configure_schedule() {
        std::cout << "\n=== 时间配置 ===" << std::endl;
        std::cout << "请输入每天执行的小时 (0-23, 北京时间, 默认: 18): ";
        
        std::string input;
        std::getline(std::cin, input);
        
        if (!input.empty()) {
            try {
                int hour = std::stoi(input);
                if (hour >= 0 && hour <= 23) {
                    config.daily_hour = hour;
                } else {
                    std::cout << "小时必须在0-23之间，使用默认值: 18" << std::endl;
                }
            } catch (const std::exception& e) {
                std::cout << "输入无效，使用默认值: 18" << std::endl;
            }
        }
        
        std::cout << "请输入每天执行的分钟 (0-59, 默认: 0): ";
        std::getline(std::cin, input);
        
        if (!input.empty()) {
            try {
                int minute = std::stoi(input);
                if (minute >= 0 && minute <= 59) {
                    config.daily_minute = minute;
                } else {
                    std::cout << "分钟必须在0-59之间，使用默认值: 0" << std::endl;
                }
            } catch (const std::exception& e) {
                std::cout << "输入无效，使用默认值: 0" << std::endl;
            }
        }
        
        std::cout << "请输入提交信息模板 (使用 {timestamp} 表示自动时间戳): ";
        std::getline(std::cin, config.commit_message_template);
        if (config.commit_message_template.empty()) {
            config.commit_message_template = "自动提交: {timestamp}";
        }
        
        save_config();
    }
    
    void process_all_repositories() {
        log("开始自动git推送任务");
        
        for (const auto& repo : config.repositories) {
            if (!repo.enabled) {
                continue;
            }
            
            log("正在处理仓库: " + repo.path);
            commit_and_push(repo);
        }
        
        log("自动git推送任务完成");
    }
    
    void start_monitoring() {
        std::cout << "\n=== 开始自动Git推送 ===" << std::endl;
        std::cout << "监控仓库数量: " << config.repositories.size() << std::endl;
        std::cout << "每天执行时间: " << config.daily_hour << ":" << std::setfill('0') << std::setw(2) << config.daily_minute << " (北京时间)" << std::endl;
        
        // Calculate and show next execution time before becoming daemon
        auto wait_time = calculate_minutes_until_next_run();
        std::cout << "下次执行时间: " << std::to_string(wait_time.count()) << " 分钟后" << std::endl;
        std::cout << "程序将在后台运行，等待定时执行" << std::endl;
        
        // Become daemon
        become_daemon();
        
        log("自动Git推送守护进程已启动，每天北京时间 " + std::to_string(config.daily_hour) + ":" + 
            (config.daily_minute < 10 ? "0" : "") + std::to_string(config.daily_minute) + " 执行");
        
        while (true) {
            auto wait_time = calculate_minutes_until_next_run();
            log("等待执行，还需 " + std::to_string(wait_time.count()) + " 分钟");
            
            // Wait until the scheduled time
            std::this_thread::sleep_for(wait_time);
            
            // Now execute the git operations at the scheduled time
            log("定时时间到达，开始执行Git操作");
            process_all_repositories();
        }
    }
    
    void run_once() {
        std::cout << "\n=== 执行一次性检查 ===" << std::endl;
        process_all_repositories();
        std::cout << "一次性检查完成。" << std::endl;
    }
    
    void show_config() {
        std::cout << "\n=== 当前配置 ===" << std::endl;
        std::cout << "执行时间: 每天北京时间 " << config.daily_hour << ":" << std::setfill('0') << std::setw(2) << config.daily_minute << std::endl;
        std::cout << "提交信息: " << config.commit_message_template << std::endl;
        std::cout << "监控仓库:" << std::endl;
        
        for (size_t i = 0; i < config.repositories.size(); i++) {
            const auto& repo = config.repositories[i];
            std::cout << "  " << (i + 1) << ". " << repo.path 
                      << " (" << repo.branch << ") " 
                      << (repo.enabled ? "[启用]" : "[禁用]") << std::endl;
        }
    }
    
    void show_menu() {
        int choice;
        
        while (true) {
            std::cout << "\n=== 自动Git推送工具 ===" << std::endl;
            std::cout << "1. 配置仓库" << std::endl;
            std::cout << "2. 配置时间" << std::endl;
            std::cout << "3. 查看当前配置" << std::endl;
            std::cout << "4. 执行一次 (测试)" << std::endl;
            std::cout << "5. 开始监控 (后台运行)" << std::endl;
            std::cout << "6. 退出" << std::endl;
            std::cout << "请选择选项 (1-6): ";
            
            std::cin >> choice;
            std::cin.ignore();
            
            switch (choice) {
                case 1:
                    configure_repositories();
                    break;
                case 2:
                    configure_schedule();
                    break;
                case 3:
                    show_config();
                    break;
                case 4:
                    if (config.repositories.empty()) {
                        std::cout << "请先配置仓库。" << std::endl;
                    } else {
                        run_once();
                    }
                    break;
                case 5:
                    if (config.repositories.empty()) {
                        std::cout << "请先配置仓库。" << std::endl;
                    } else {
                        start_monitoring();
                    }
                    break;
                case 6:
                    std::cout << "再见！" << std::endl;
                    return;
                default:
                    std::cout << "无效选择，请重试。" << std::endl;
                    break;
            }
        }
    }
};

int main() {
    AutoGitPush auto_pusher;
    auto_pusher.show_menu();
    return 0;
}
